package com.ht.filter;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.TypeReference;
import com.ht.abnormal.HtException;
import com.ht.abnormal.ValidateCodeException;
import com.ht.config.security.MyUserDetailsService;
import com.ht.config.security.handler.LocalAccessDeniedHandler;
import com.ht.config.security.handler.LocalAuthenticationFailureHandler;
import com.ht.constant.BusConstant;
import com.ht.constant.RedisConstants;
import com.ht.module.sys.entity.SysUser;
import com.ht.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;


/**
 * @ProjectName: ht
 * @ClassName: JwtAuthenticationTokenFilter
 * @Author: hejialun
 * @Description: JWT验证过滤器
 * @Date: 2021/6/20 16:51
 */
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MyUserDetailsService myUserDetailsService;
    @Autowired
    private LocalAuthenticationFailureHandler localAuthenticationFailureHandler;
    //token过期时间
    @Value("${jwt.expireTime}")
    public long EXPIRE_TIME;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //登录验证码判断
        Boolean pd=loginCheck(request,response);
        //token权限设置
        String token  = UserUtil.getTokenByRequest(request);

        if(StrUtil.isNotEmpty(token)){
            //去redis里面获取token信息
            Map<String, Object> map = (Map<String, Object>) redisUtil.get(RedisConstants.USER_INFOS_PREFIX + token);
            if(ObjectUtil.isNotEmpty(map)){
                //判断token是否过期
                String username = map.get("username").toString();
                try {
                    //重新查询用户
                    UserDetails userDetails = myUserDetailsService.loadUserByUsername(username);
                    //设置权限
                    if (userDetails != null) {
                        //刷新token过期时间
                        redisUtil.expire(RedisConstants.USER_INFOS_PREFIX + token,EXPIRE_TIME);
                        UsernamePasswordAuthenticationToken authentication =
                                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                } catch (Exception e) {
                    response.setCharacterEncoding("utf-8");
                    response.setContentType("application/json;charset=utf-8");
                    response.getWriter().print(JSON.toJSONString(JsonResult.error(e.getMessage())));
                    return;
                }
            }else{
                response.setCharacterEncoding("utf-8");
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().print(JSON.toJSONString(JsonResult.error(ResultEnum.LOGIN_IS_OVERDUE.getMessage(),ResultEnum.LOGIN_IS_OVERDUE.getCode())));
                return;
            }
        }
        if(pd){
            filterChain.doFilter(request, response);
        }

    }


    /**
     * 登录校验
     * @param request
     */
    public Boolean loginCheck(HttpServletRequest request,HttpServletResponse response) throws IOException {
        Boolean pd=true;
        //登陆验证码
        if (StrUtil.equals("/back/login", request.getRequestURI()) && StrUtil.equalsIgnoreCase(request.getMethod(), "post")) {
            //获取验证码值
            String requestCaptcha = request.getParameter("code");
            //获取随机值
            String randomStr = request.getParameter("randomStr");
            try{
                if (requestCaptcha == null) {
                    pd=false;
                    throw new ValidateCodeException(BusConstant.VERIFICATION_CODE_NOT_EXIST);
                }
                String code = (String) redisUtil.get(RedisConstants.VERIFICATION_CODE_PREFIX+randomStr);
                if (StrUtil.isEmpty(code)) {
                    pd=false;
                    throw new ValidateCodeException(BusConstant.VERIFICATION_CODE_PAST);
                }
                code = code.equals("0.0") ? "0" : code;
                if (!StrUtil.equals(code, requestCaptcha)) {
                    pd=false;
                    throw new ValidateCodeException(BusConstant.VERIFICATION_CODE_NOT_CORRECT);
                }
            }catch (AuthenticationException e){
                pd=false;
                localAuthenticationFailureHandler.onAuthenticationFailure(request,response,  e);
            }

        }
        return pd;
    }

}